package common;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

public class IndexWordUtil {
  /** Sets the custom break characters set by the user */
  private Map customBreakChars = null;
    
  public IndexWordUtil(char[] breakChars) {
    HashMap customBreakChars = new HashMap();
    for (int i = 0; i < breakChars.length; i++) {
      customBreakChars.put(new Character(breakChars[i]), new Object());
    }
    this.customBreakChars = customBreakChars;
  }
  
  /**
   * Gets the next word from an input stream.
   * 
   * @param stream input stream to read from
   * @return next word in input stream or null if the end of stream was reached
   * @throws IOException
   */
  public String getNextWord(BufferedInputStream stream) throws IOException {
    String word = "";

    clearBreakCharacters(stream);
    for (int nextChar = Util.peek(stream); 
         nextChar != Constants.EOF && !isBreakCharacter(nextChar); 
         nextChar = Util.peek(stream)) {
      word += (char) stream.read();
    }
    return word.equals("") ? null : word;
  }
  
  /**
   * Gets the next word from an input stream.
   * 
   * @param reader input stream to read from
   * @return next word in input stream or null if the end of stream was reached
   * @throws IOException
   */
  public String getNextWord(StringReader reader) throws IOException {
    String word = "";

    clearBreakCharacters(reader);
    for (int nextChar = Util.peek(reader); 
         nextChar != Constants.EOF && !isBreakCharacter(nextChar); 
         nextChar = Util.peek(reader)) {
      word += (char) reader.read();
    }
    return word.equals("") ? null : word;
  }
  
  /**
   * This method tests <code>toCheck</code> against both the fixed and
   * variable sets of break characters.
   * 
   * @param toCheck will be tested to see if it is a break character
   * @return <code>true</code> if <code>toCheck</code> is a break character,
   *         <code>false</code> otherwise
   * @throws IOException
   */
  public boolean isBreakCharacter(int toCheck) throws IOException {
    boolean isBreakChar = false;
    Character key = new Character((char) toCheck);
    isBreakChar = (customBreakChars.get(key) != null);
    isBreakChar = isBreakChar || 
                  toCheck < Constants.FIRST_CUSTOM_BC || 
                  toCheck > Constants.LAST_CUSTOM_BC;
    return isBreakChar;
  }

  /**
   * Reads an input stream until a non-break character or EOF is encountered.
   * 
   * @param fis Input stream to read
   * @throws IOException
   */
  private void clearBreakCharacters(BufferedInputStream stream) throws IOException {
    for(int nextChar = Util.peek(stream); 
        nextChar != Constants.EOF && isBreakCharacter(nextChar); 
        nextChar = Util.peek(stream)) {
      stream.skip(1);
    }
  }
  
  /**
   * Reads an input stream until a non-break character or EOF is encountered.
   * 
   * @param fis Input stream to read
   * @throws IOException
   */
  private void clearBreakCharacters(StringReader reader) throws IOException {
    for(int nextChar = Util.peek(reader); 
        nextChar != Constants.EOF && isBreakCharacter(nextChar); 
        nextChar = Util.peek(reader)) {
      reader.skip(1);
    }
  }

}